/******************************************************************************
* Copynext (c) 2007 Alexandru Scvortov
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the nexts
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copynext notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYnext HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/


#include "common.h"
#include <string.h>

static void add_to_function_list(FunctionNode *node) {
    FunctionNode *it = functions;
    FunctionNode *pr = 0;
    while (it && (strcmp(node->name->value, it->name->value) > 0)) {
        pr = it;
        NEXT(it);
    }

    if (it && (0 == strcmp(node->name->value, it->name->value))) {
        it->c_node = node->c_node;
        return;
    }

    if (pr)
        pr->next = node;
    else
        functions = node;
    node->next = it;
}

WordNode* word_node_new() {
    WordNode *tmp = (WordNode*)malloc(sizeof(WordNode));

    tmp->type = WordNodeUnknown;
    tmp->value = 0;
    tmp->next = 0;

    return tmp;
}

WordNode* word_node_remove(WordNode *wn) {
    if (!wn)
        return 0;

    check_and_free(wn->value);

    check_and_free(wn);

    return wn;
}

static FunctionNode* function_node_new() {
    FunctionNode *tmp = (FunctionNode*)malloc(sizeof(FunctionNode));

    tmp->child = 0;
    tmp->next = 0;
    tmp->c_node = 0;
    tmp->name = 0;
	tmp->line_num = 0;
	tmp->file_name = 0;

    return tmp;
}

FunctionNode* function_node_remove(FunctionNode *fn) {
    if (!fn)
        return 0;

    WordNode *it;
    it = fn->child;
    while (it) {
        WordNode *next = it->next;
        word_node_remove(it);
        it = next;
    }

    check_and_free(fn);

    return fn;
}

static char current_separator;
static char *next;
static char* get_first_separator(char *text, char *sep) {
    if (!text || (!text[0]))
        if (!next)
            return 0;
        else
            text = next + 1;

    char *c = text;
    while (*c) {
        char *s = sep;
        while (*s) {
            if (*s == *c) {
                current_separator = *c;
                *c = 0;
                next = c;
                return text;
            }
            ++s;
        }
        ++c;
    }

    current_separator = 0;
    next = 0;
    return text;
}

static WordNode* split_function(char *text) {
    if (current_separator && (' ' != current_separator) && ('{' != current_separator)) {
        WordNode *tmp = word_node_new();
        tmp->value = (char*)malloc(2 * sizeof(char));
        tmp->value[0] = current_separator;
        tmp->value[1] = 0;
        current_separator = 0;
        tmp->next = split_function(0);
        return tmp;
    }

    char *n = get_first_separator(text, " *(){,");
    if (!n)
        return 0;
    else {
        WordNode *tmp;
        if (strlen(n)) {
            tmp = word_node_new();
            tmp->value = (char*)malloc((strlen(n) + 1) * sizeof(char));
            strcpy(tmp->value, n);
            tmp->next = split_function(0);

            // Check if this is the function name
            if ((tmp->next) && ('(' == tmp->next->value[0]))
                tmp->type = WordNodeName;

            // Check if this is some special keyword
            if (0 == strcmp(tmp->value, "static"))
                tmp->type = WordNodeFunctionType;
        } else
            tmp = split_function(0);

        return tmp;
    }
}

void parse_function() {
    next = 0;
    current_separator = 0;
    FunctionNode *fn = function_node_new();
    fn->child = split_function(current_value);

    WordNode *it = fn->child;
    while (it) {
        if (WordNodeName == it->type) {
            fn->name = it;
            break;
        }
        NEXT(it);
    }

    if (comments && !comments->assigned) {
        fn->c_node = comments;
        comments->assigned = 1;
    } else {
        if (fn->name->value)
            fprintf(stderr, "W: Declaration of function %s has no comment.\n", fn->name->value);
    }

	fn->line_num = cur_line_num;
	fn->file_name = current_file;

    add_to_function_list(fn);
}
